/*
 * Gedigarr - Falling block game.
 * Copyright (C) 2010  BoredCorp
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
package gedigarr.game;

import gedigarr.resources.GameResource;
import gedigarr.resources.ResourceManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 *
 * Initial revision - 2010-04-08
 * 
 * @author JC
 */
public class GameScore {

  public static final int HI_SCORES = 10;
  private static final String HI_KEY = "score";
  private static final String PAIR_SEPARATOR = "=";
  private static final String VALUE_SEPARATOR = ",";
  private static final String NEW_LINE = System.getProperty( "line.separator" );
  private long hiScore = 0L;
  private long score = 0L;
  private Score[] hiScores = new Score[ HI_SCORES ];
  GameResource scoreResource;

  public GameScore() {
    scoreResource = ResourceManager.getInstance().retrieveFile( "scores.dat", ResourceManager.LOC_FS, ResourceManager.ACCESS_WRITABLE );
    for ( int i = 0; i < HI_SCORES; i++ ) {
      hiScores[i] = new Score();
    }
    readResource();
    this.hiScore = hiScores[0].score;
  }

  public void resetScore() {
    this.score = 0L;
  }

  /**
   * Retrieve the current game score.
   * @return
   */
  public long getScore() {
    return this.score;
  }

  public Score[] getHiScores() {
    return this.hiScores;
  }

  /**
   * Retrieve the location on the leaderboard this sampleScore would be placed.
   * <p>
   * Returns -1 if the score is too low.
   * @param sampleScore
   * @return
   */
  public int getBoardPosition( long sampleScore ) {
    for ( int i = 0; i < HI_SCORES; i++ ) {
      long current = hiScores[i].score;
      //if current belongs in this space
      if ( sampleScore > current ) {
        return i + 1; // offset for 0-based array.
      }
    }
    return -1;
  }

  /**
   * Retrieve the all time top score.
   * @return
   */
  public long getHighScore() {
    return this.hiScore;
  }

  public long getHighScore( int place ) {
    return this.hiScores[place].score;
  }

  public void setScore( long score ) {
    if ( score > this.hiScore ) {
      this.hiScore = score;
    }
    this.score = score;
  }

  public void addToScore( long points ) {
    setScore( this.score + points );
  }

  public void addHiScore( String name, long score, int level, long time ) {
    Score sort = new Score( name, score, level, time );
    for ( int i = 0; i < HI_SCORES; i++ ) {
      Score current = hiScores[i];
      //if current belongs in this space
      if ( sort.score > current.score ) {
        hiScores[i] = sort;
        sort = current;
      }
    }

    writeResource();
  }

  public String getScoreString() {
    StringBuffer sb = new StringBuffer();

    for ( Score hi : hiScores ) {
      sb.append( HI_KEY ).append( PAIR_SEPARATOR );
      sb.append( hi.name ).append( VALUE_SEPARATOR );
      sb.append( hi.score ).append( VALUE_SEPARATOR );
      sb.append( hi.level ).append( VALUE_SEPARATOR );
      sb.append( hi.time ).append( NEW_LINE );
    }

    return sb.toString();
  }

  public boolean readResource() {
    File f = (File) scoreResource.getResource();
    BufferedReader read = null;
    String line = null;
    try {
      if ( f.exists() ) {
        read = new BufferedReader( new FileReader( f ) );
        int count = 0;
        line = read.readLine();
        while ( line != null && count < HI_SCORES ) {
          if ( parseScoreLine( line ) ) {
            count++;
          }
          line = read.readLine();
        }
      }
    } catch ( IOException ex ) {
      ex.printStackTrace();
      return false;
    }

    return true;
  }

  private boolean parseScoreLine( String line ) {
    String[] pair = line.split( PAIR_SEPARATOR );
    String[] values = null;
    //>< 2 means malformed, ignore and return fail.
    if ( pair.length != 2 ) {
      return false;
    }

    //is a score key-value pair
    if ( pair[0].equalsIgnoreCase( HI_KEY ) ) {
      values = pair[1].split( VALUE_SEPARATOR );
      if ( values.length != 4 ) {
        return false;
      }

      addHiScore( values[0], Long.parseLong( values[1] ),
              Integer.parseInt( values[2] ), Long.parseLong( values[3] ) );
    }
    return true;
  }

  public boolean writeResource() {
    File f = (File) scoreResource.getResource();
    FileWriter fw = null;
    try {
      if ( !f.exists() ) {
        f.createNewFile();
      }

      if ( f.canWrite() ) {
        fw = new FileWriter( f );
        fw.write( getScoreString() );
        fw.close();
      }
    } catch ( IOException ex ) {
      return false;
    }

    return true;
  }

  public static void main( String[] args ) {
    GameScore gs = new GameScore();
    System.out.println( gs.getScoreString() );
  }

  public class Score {

    public long score;
    public String name;
    public int level;
    public long time;

    public Score() {
      this( "", 0L, 0, 0L );
    }

    public Score( String name, long score, int level, long time ) {
      this.name = name;
      this.score = score;
      this.level = level;
      this.time = time;
    }
  }
}
